/*
 * Copyright (C) 2020 UNISOC Open Source Project
 *
 */

package com.unisoc.systemui.screenshot;

import android.graphics.Bitmap;
import android.util.Log;
import android.graphics.Color;

import java.util.Iterator;
import java.util.ArrayList;
import java.util.Collections;
import java.lang.Math;

public class CompareUtils {
    private static final String TAG = "CompareUtils";

    private static final int SCREENSHOT_LEFT_MARGIN = 120;
    private static final int SCREENSHOT_RIGHT_MARGIN = 120;
    private static final int SCALE = 2;
    private static final double SIMILARITY_PERCENT_MOST_EXACTLY = 0.95;
    private static final int DIFF_EXACTLY = 5;
    private static final int RGB_EXACTLY = 30;
    public static final int COMPARE_IGNORE_DISTANCE = 3;

    /*UNISOC: Modify for bug 1361055 @{*/
    public static boolean CompareCropedBitmap(Bitmap first, Bitmap second, float scale) {
        if (first == null || second == null) return false;
        int screenWidth = first.getWidth();
        int screenHeight = first.getHeight();

        int header = (int)(screenHeight / 4 * scale);
        int bottom = (int)(screenHeight / 4 * scale);

        int left = SCREENSHOT_LEFT_MARGIN;
        int right = SCREENSHOT_RIGHT_MARGIN;

        /* UNISOC: Modify for bug1404134 @{ */
        try {
            Bitmap bitmap1 = Bitmap.createBitmap(first, left, header,
                    screenWidth - left - right,
                    screenHeight - header - bottom);
            Bitmap bitmap2 = Bitmap.createBitmap(second, left, header,
                    screenWidth - left - right,
                    screenHeight - header - bottom);
            boolean isSameAs = bitmap1.sameAs(bitmap2);
            Log.i(TAG, "isSameAs:" + isSameAs);
            bitmap1.recycle();
            bitmap2.recycle();
            return isSameAs;
        } catch (IllegalArgumentException e) {
            Log.e(TAG, "createBitmap() size error: width = " + (screenWidth - left - right)
                    + ", height = " + (screenHeight - header - bottom));
            return true;
        }
        /* @} */
    }

    public static int computeMoveDistance(Bitmap first, Bitmap second, float scale) {
        if (first == null || second == null) return -1;

        int screenWidth = first.getWidth();
        int screenHeight = first.getHeight();

        int header = (int)(screenHeight / 4 * scale);
        int bottom = (int)(screenHeight / 4 * scale);

        int left = SCREENSHOT_LEFT_MARGIN;
        int right = SCREENSHOT_RIGHT_MARGIN;

        Bitmap bitmap1 = Bitmap.createBitmap(first, left, header,
                screenWidth - left - right,
                screenHeight - header - bottom);
        Bitmap bitmap2 = Bitmap.createBitmap(second, left, header,
                screenWidth - left - right,
                screenHeight - header - bottom);

        int width = bitmap1.getWidth();
        int height = bitmap1.getHeight();

        Bitmap tmp1 = null;
        Bitmap tmp2 = null;

        int fragmentHeight = height / 5;
        int distance = -1;
        int cmpHeight = height - fragmentHeight;
        Log.d(TAG, "fragmentHeight:" + fragmentHeight + " cmpHeight:" + cmpHeight);

        tmp1 = Bitmap.createBitmap(bitmap1, 0, height - fragmentHeight, width, fragmentHeight);

        ArrayList<Similar> list = new ArrayList<Similar>();
        int value = -1;

        for (int i = 0; i <= cmpHeight; i++) {
            tmp2 = Bitmap.createBitmap(bitmap2, 0, i, width, fragmentHeight);

            value = tmp1.similar(tmp2, DIFF_EXACTLY);
            tmp2.recycle();

            if (value == -1) {
                continue;
            } else if (value == 0) {
                distance = i + fragmentHeight;
                break;
            } else {
                Similar s = new Similar(value, i);
                list.add(s);
            }
        }

        //If can not match exactly, then use the most similar index.
        if (distance == -1 && list.size() > 0) {
            Collections.sort(list);

            distance = list.get(0).index + fragmentHeight;
            Log.w(TAG, "Diff value is " + list.get(0).diff + " index:" + list.get(0).index);
        } else if (distance == -1) {
            Bitmap scale1 = Bitmap.createScaledBitmap(tmp1, tmp1.getWidth() / SCALE, tmp1.getHeight() / SCALE, true);
            ArrayList<Percentage> l = new ArrayList<Percentage>();

            for (int i = 0; i <= cmpHeight; i++) {
                tmp2 = Bitmap.createBitmap(bitmap2, 0, i, width, fragmentHeight);
                Bitmap scale2 = Bitmap.createScaledBitmap(tmp2, tmp2.getWidth() / SCALE, tmp2.getHeight() / SCALE, true);
                double p = similarityPercentage(scale1, scale2);
                tmp2.recycle();
                scale2.recycle();

                if (p > SIMILARITY_PERCENT_MOST_EXACTLY) {
                    Percentage percentage = new Percentage(p, i);
                    l.add(percentage);
                }
            }
            scale1.recycle();

            if (l.size() > 0) {
                Collections.sort(l);

                distance = l.get(0).index + fragmentHeight;
                Log.w(TAG, "Most similar percent:" + l.get(0).percent + " index:" + l.get(0).index);
            }
        }

        tmp1.recycle();
        bitmap1.recycle();
        bitmap2.recycle();
        Log.d(TAG, "distance:" + distance);
        return distance;
    }
    /*}@*/

    private static double similarityPercentage(Bitmap bitmap1, Bitmap bitmap2) {
        int width = bitmap1.getWidth();
        int height = bitmap1.getHeight();
        int count = 0;

        final int size = width * height;
        int[] pexels1 = new int[size];
        int[] pexels2 = new int[size];

        bitmap1.getPixels(pexels1, 0, width, 0, 0, width, height);
        bitmap2.getPixels(pexels2, 0, width, 0, 0, width, height);

        for (int i = 0; i < size; i++) {
            int color1 = pexels1[i];
            int color2 = pexels2[i];

            int rDeviation = Math.abs(Color.red(color1) - Color.red(color2));
            int gDeviation = Math.abs(Color.green(color1) - Color.green(color2));
            int bDeviation = Math.abs(Color.blue(color1) - Color.blue(color2));

            int avg = (rDeviation + gDeviation + bDeviation) / 3;
            if (avg < RGB_EXACTLY) {
                count++;
            }
        }
        return (double)count / (double)size;
    }

    public static boolean isFHDScreen(final Bitmap bitmap) {
        return (bitmap != null) && (bitmap.getWidth() >= 1080);
    }
}

class Similar implements Comparable {
    public int diff;
    public int index;

    public Similar(int diff, int index) {
        this.diff = diff;
        this.index = index;
    }

    public int compareTo(Object o) {
        return this.diff - ((Similar) o).diff;
    }
}

class Percentage implements Comparable {
    public double percent;
    public int index;

    public Percentage(double percent, int index) {
        this.percent = percent;
        this.index = index;
    }

    public int compareTo(Object o) {
        if (this.percent < ((Percentage) o).percent) return 1;
        if (this.percent > ((Percentage) o).percent) return -1;
        return 0;
    }
}
